home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-09-28 | 52.2 KB | 1,737 lines |
- {------------------------------------------------------------------------------
- #
- # Apple Macintosh Developer Technical Support
- #
- # MultiFinder-Aware Simple Styled TextEdit Sample Application
- #
- # TEStyleSample
- #
- # TEStyleSample.p - Pascal Source
- #
- # Copyright © 1989 Apple Computer, Inc.
- # All rights reserved.
- #
- # Versions: 1.0 10/89
- #
- # Components: TEStyleSample.p October 1, 1989
- # TEStyleSampleGlue.a October 1, 1989
- # TEStyleSample.r October 1, 1989
- # TEStyleSample.h October 1, 1989
- # PTEStyleSample.make October 1, 1989
- #
- # TEStyleSample is an example application that demonstrates how
- # to initialize the commonly used toolbox managers, operate
- # successfully under MultiFinder, handle desk accessories and
- # create, grow, and zoom windows. Both styled and fundamental TextEdit
- # toolbox calls and TextEdit autoscroll are demonstrated. It
- # also shows how to create and maintain scrollbar controls as well
- # as implementing a basic printing loop.
- #
- # It does not by any means demonstrate all the techniques you
- # need for a large application. In particular, TEStyleSample does not
- # cover exception handling, multiple windows/documents,
- # sophisticated memory management, or undo. All of
- # these are vital parts of a normal full-sized application.
- #
- # This application is an example of the form of a Macintosh
- # application; it is NOT a template. It is NOT intended to be
- # used as a foundation for the next world-class, best-selling,
- # 600K application. A stick figure drawing of the human body may
- # be a good example of the form for a painting, but that does not
- # mean it should be used as the basis for the next Mona Lisa.
- #
- # We recommend that you review this program, TESample or Sample before
- # beginning a new application. TESample is a simpler version of TEStyleSample
- # without styles and Sample is a simple app. which doesn’t
- # use TextEdit or the Control Manager.
- #
- ------------------------------------------------------------------------------}
-
-
- PROGRAM TEStyleSample;
-
- {Segmentation strategy:
-
- This program consists of three segments. Main contains most of the code,
- including the MPW libraries, and the main program. Initialize contains
- code that is only used once, during startup, and can be unloaded after the
- program starts. %A5Init is automatically created by the Linker to initialize
- globals for the MPW libraries and is unloaded right away.}
-
-
- {SetPort strategy:
-
- Toolbox routines do not change the current port. In spite of this, in this
- program we use a strategy of calling SetPort whenever we want to draw or
- make calls which depend on the current port. This makes us less vulnerable
- to bugs in other software which might alter the current port (such as the
- bug (feature?) in many desk accessories which change the port on OpenDeskAcc).
- Hopefully, this also makes the routines from this program more self-contained,
- since they don't depend on the current port setting.}
-
-
- {Clipboard strategy:
-
- Under styled TextEdit, TECut and TECopy will write both the text and associated
- style information directly to the desk scrap as types 'TEXT' and 'styl'.
- Instead of using TEToScrap and TEFromScrap, a new routine TEStylePaste, will
- transfer the text and style from the desk scrap to the document. }
-
- {$D+}
-
- USES
- Types, QuickDraw, Events, Controls, Windows, TextEdit, Dialogs, Fonts, Lists,
- Menus, Resources, Scrap, ToolUtils,
- OSUtils, Files, Devices, DeskBus, DiskInit, Disks, Errors, Memory, Retrace, SegLoad, Serial,
- ShutDown, Slots, Sound, Start, Timer, Packages, Traps, Printing;
-
- CONST
-
- {kTextMargin is the number of pixels we leave blank at the edge of the window.}
- kTextMargin = 2;
-
- {kMaxOpenDocuments is used to determine whether a new document can be opened
- or created. We keep track of the number of open documents, and disable the
- menu items that create a new document when the maximum is reached. If the
- number of documents falls below the maximum, the items are enabled again.}
- kMaxOpenDocuments = 1;
-
- {kMaxDocWidth is an arbitrary number used to specify the width of the TERec's
- destination rectangle so that word wrap and horizontal scrolling can be
- demonstrated.}
- kMaxDocWidth = 576;
-
- {kMinDocDim is used to limit the minimum dimension of a window when GrowWindow
- is called.}
- kMinDocDim = 64;
-
- {kControlInvisible is used to 'turn off' controls (i.e., cause the control not
- to be redrawn as a result of some Control Manager call such as SetControlValue)
- by being put into the contrlVis field of the record. kControlVisible is used
- the same way to 'turn on' the control.}
- kControlInvisible = 0;
- kControlVisible = $FF;
-
- {kScrollBarAdjust and kScrollBarWidth are used in calculating
- values for control positioning and sizing.}
- kScrollbarWidth = 16;
- kScrollbarAdjust = kScrollbarWidth - 1;
-
- {kScrollTweek compensates for off-by-one requirements of the scrollbars
- to have borders coincide with the growbox.}
- kScrollTweek = 2;
-
- {kCrChar is used to match with a carriage return when calculating the
- number of lines in the TextEdit record. kDelChar is used to check for
- delete in keyDowns.}
- kCRChar = 13;
- kDelChar = 8;
-
- {kButtonScroll is how many pixels to scroll horizontally when the button part
- of the horizontal scrollbar is pressed.}
- kButtonScroll = 4;
-
- {kMaxTELength is an arbitrary number used to limit the length of text in the TERec
- so that various errors won't occur from too many characters in the text.}
- kMaxTELength = 32000;
- (* what about that tech note I wrote? is this a valid check anymore? maw *)
-
- {kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the
- SysEnvRec we understand.}
- kSysEnvironsVersion = 1;
-
- {kOSEvent is the event number of the suspend/resume and mouse-moved events sent
- by MultiFinder. Once we determine that an event is an osEvent, we look at the
- high byte of the message sent to determine which kind it is. To differentiate
- suspend and resume events we check the resumeMask bit.}
- kOSEvent = app4Evt; { event used by MultiFinder }
- kSuspendResumeMessage = 1; { high byte of suspend/resume event message }
- kResumeMask = 1; { bit of message field for resume vs. suspend }
- kMouseMovedMessage = $FA; { high byte of mouse-moved event message }
- kNoEvents = 0; {no events mask}
-
- {kMinHeap - This is the minimum result from the following
- equation:
-
- ORD(GetApplLimit) - ORD(ApplicationZone)
-
- for the application to run. It will insure that enough memory will
- be around for reasonable-sized scraps, FKEYs, etc. to exist with the
- application, and still give the application some 'breathing room'.
- To derive this number, we ran under a MultiFinder partition that was
- our requested minimum size, as given in the 'SIZE' resource.}
-
- kMinHeap = 29 * 1024;
-
- {kMinSpace - This is the minimum result from PurgeSpace, when called
- at initialization time, for the application to run. This number acts
- as a double-check to insure that there really is enough memory for the
- application to run, including what has been taken up already by
- pre-loaded resources, the scrap, code, and other sundry memory blocks.}
-
- kMinSpace = 20 * 1024;
-
- {kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions.}
- kExtremeNeg = -32768;
- kExtremePos = 32767 - 1; { required for old region bug }
-
- {kTESlop provides some extra security when pre-flighting edit commands.}
- kTESlop = 1024;
-
- {kErrStrings is the resource ID for the error strings STR# resource.}
- kErrStrings = 128;
-
- { The following are indicies into STR# resources. }
- eWrongMachine = 1;
- eSmallSize = 2;
- eNoMemory = 3;
- eNoSpaceCut = 4;
- eNoCut = 5;
- eNoCopy = 6;
- eExceedPaste = 7;
- eNoSpacePaste = 8;
- eNoWindow = 9;
- eExceedChar = 10;
- eNoPaste = 11;
-
-
- { The following constants are all resource IDs, corresponding to their resources }
-
- rMenuBar = 128; { application's menu bar }
- rAboutAlert = 128; { about alert }
- rUserAlert = 129; { user error alert }
- rDocWindow = 128; { application's window }
-
- rVScroll = 128; { vertical scrollbar control }
- rHScroll = 129; { horizontal scrollbar control }
-
-
- { The following constants are all menu and item IDs corresponding to their resources }
-
- mApple = 128; { Apple menu }
- iAbout = 1;
-
- mFile = 129; { File menu }
- iNew = 1;
- iClose = 4;
- iPageSetup = 9; { Added for TEStyleSample }
- iPrint = 10; { Added for TEStyleSample }
- iQuit = 12;
-
- mEdit = 130; { Edit menu }
- iUndo = 1;
- iCut = 3;
- iCopy = 4;
- iPaste = 5;
- iClear = 6;
- iSelectAll = 8; { Added for TEStyleSample }
-
- mFont = 131; { Font menu-added for TEStyleSample }
-
- mFontSize = 132; { Font size menu-added for TEStyleSample }
- iNine = 1;
- iTen = 2;
- iTwelve = 3;
- iFourteen = 4;
- iEighteen = 5;
- iTwoFour = 6;
-
- mStyle = 133; { Style menu-added for TEStyleSample }
- iPlain = 1;
- iBold = 3;
- iItalic = 4;
- iUnderline = 5;
- iOutline = 6;
- iShadow = 7;
-
- {kDITop and kDILeft are used to locate the Disk Initialization dialogs.}
- kDITop = $0050;
- kDILeft = $0070;
-
-
- TYPE
- {A DocumentRecord contains the WindowRecord for one of our document windows,
- as well as the TEHandle for the text we are editing. We have added fields to
- hold the ControlHandles to the vertical and horizontal scrollbars and to hold
- the address of the default clickLoop that gets attached to a TERec when you call
- TEAutoView. Other document fields can be added to this record as needed. For
- a similar example, see how the Window Manager and Dialog Manager add fields
- after the GrafPort.}
- DocumentRecord = RECORD
- docWindow : WindowRecord;
- docTE : TEHandle;
- docVScroll : ControlHandle;
- docHScroll : ControlHandle;
- docClick : TEClickLoopUPP;
- END;
- DocumentPeek = ^DocumentRecord;
-
-
- VAR
- {The "g" prefix is used to emphasize that a variable is global.}
- gMac : SysEnvRec; { set up by Initialize }
- gHasWaitNextEvent : BOOLEAN; { set up by Initialize }
- gInBackground : BOOLEAN; { maintained by Initialize and DoEvent }
- gNumDocuments : INTEGER; { maintained by Initialize, DoNew, and DoCloseWindow }
-
- {New globals to support printing and style selection }
- gTxStyle : TextStyle; { holds style selected, plain default, maintained by DoMenuCommand }
- gFontName : Str255; { name of font selected, app font default, maintained by DoMenuCommand }
- gFontID : INTEGER; { ID of font selected, app font default, maintained by DoMenuCommand }
- gFontSize : LONGINT; { font size selected, 12 pt default, maintained by DoMenuCommand }
- gPrinterRecord : THPrint; { print handle, maintained by printText }
- gPrinterPort : TPPrPort; { pointer to Print Manager's GrafPort }
-
-
-
- {$S Initialize}
- FUNCTION TrapAvailable(tNumber: INTEGER; tType: TrapType): BOOLEAN;
-
- {Check to see if a given trap is implemented. This is only used by the
- Initialize routine in this program, so we put it in the Initialize segment.
- The recommended approach to see if a trap is implemented is to see if
- the address of the trap routine is the same as the address of the
- Unimplemented trap.}
- {Needs to be called after call to SysEnvirons so that it can check
- if a ToolTrap is out of range of a pre-MacII ROM.}
-
- BEGIN
- IF (tType = ToolTrap) &
- (gMac.machineType > envMachUnknown) &
- (gMac.machineType < envMacII) THEN BEGIN {it's a 512KE, Plus, or SE}
- tNumber := BAND(tNumber, $03FF);
- IF tNumber > $01FF THEN {which means the tool traps}
- tNumber := _Unimplemented; {only go to $01FF}
- END;
- TrapAvailable := NGetTrapAddress(tNumber, tType) <>
- NGetTrapAddress(_Unimplemented, ToolTrap);
- END; {TrapAvailable}
-
-
- {$S Main}
- FUNCTION IsDAWindow( window : WindowPtr ) : BOOLEAN;
-
- { Check if a window belongs to a desk accessory. }
-
- BEGIN { IsDAWindow }
- IF window = NIL THEN
- IsDAWindow := FALSE
- ELSE { DA windows have negative windowKinds }
- IsDAWindow := WindowPeek( window )^.windowKind < 0;
- END; { IsDAWindow }
-
-
-
- {$S Main}
- FUNCTION IsAppWindow( window : WindowPtr ) : BOOLEAN;
-
- { Check if a window belongs to the application. }
-
- BEGIN { IsAppWindow }
- IF window = NIL THEN
- IsAppWindow := FALSE
- ELSE { application windows have non-negative windowKinds }
- IsAppWindow := WindowPeek( window )^.windowKind >= 0;
- END; { IsAppWindow }
-
-
-
- {$S Main}
- PROCEDURE AlertUser( error : INTEGER );
-
- { Display an alert that tells the user an error occurred, then exit the program }
-
- VAR
- itemHit : INTEGER;
- message : Str255;
-
- BEGIN { AlertUser }
- SetCursor( qd.arrow );
- GetIndString( message, kErrStrings, error );
- ParamText(message, '', '', '');
- itemHit := Alert( rUserAlert, NIL );
- END; { AlertUser }
-
-
-
- {$S Main}
- PROCEDURE GetTERect( window : WindowPtr; VAR teRect : Rect);
-
- { return a rectangle that is inset from the portRect by the size of
- the scrollbars and a little extra margin. }
-
- BEGIN { GetTERect }
- teRect := window^.portRect;
- InsetRect( teRect, kTextMargin, kTextMargin ); { adjust for margin }
- teRect.bottom := teRect.bottom - kScrollbarAdjust; { and for the scrollbars }
- teRect.right := teRect.right - kScrollbarAdjust;
- END; { GetTERect }
-
-
-
- {$S Main}
- FUNCTION DoCloseWindow( window : WindowPtr ) : BOOLEAN;
-
- { Close a window. This handles desk accessory and application windows. }
-
- BEGIN { DoCloseWindow }
- DoCloseWindow := TRUE;
- IF IsDAWindow( window ) THEN
- CloseDeskAcc( WindowPeek( window )^.windowKind )
- ELSE IF IsAppWindow( window ) THEN BEGIN
- WITH DocumentPeek( window )^ DO
- IF docTE <> NIL THEN
- TEDispose( docTE );
- CloseWindow( window );
- DisposePtr( Ptr( window ) );
- gNumDocuments := gNumDocuments - 1;
- END;
- END; { DoCloseWindow }
-
-
-
- {$S Main}
- PROCEDURE AdjustTE( window : WindowPtr );
-
- { Scroll the TERec around to match up to the potentially updated scrollbar
- values. This is really useful when the window resizes such that the
- scrollbars become inactive and the TERec had been previously scrolled. }
-
- VAR
- value : INTEGER;
-
- BEGIN { AdjustTE }
- WITH DocumentPeek( window )^ DO BEGIN
- TEScroll( ( docTE^^.viewRect.left - docTE^^.destRect.left ) - GetControlValue( docHScroll ),
- ( docTE^^.viewRect.top - docTE^^.destRect.top ) -
- GetControlValue( docVScroll ) , docTE );
- END; { with }
- END; { AdjustTE }
-
-
-
- {$S Main}
- PROCEDURE AdjustHV( isVert : BOOLEAN; control : ControlHandle;
- docTE : TEHandle; canRedraw : BOOLEAN );
-
- {Calculate the new control maximum value and current value, whether it is the horizontal or
- vertical scrollbar. The vertical max is calculated by comparing the number of lines to the
- vertical size of the viewRect. The horizontal max is calculated by comparing the maximum document
- width to the width of the viewRect. The current values are set by comparing the offset between
- the view and destination rects. If necessary and we canRedraw, have the control be re-drawn by
- calling ShowControl.}
-
- {TEStyleSample-vertical max originally used line by line calculations-lineheight was a
- constant value so it was easy to figure out what the range should be and pin the value
- within range. Now we need to use max and min values in pixels rather than in nlines}
-
- VAR
- value, max : INTEGER;
- oldValue, oldMax : INTEGER;
-
- BEGIN { AdjustHV }
- oldValue := GetControlValue( control );
- oldMax := GetControlMaximum( control );
- IF isVert THEN BEGIN
- { new for TEStyleSample }
- max := ( TEGetHeight( docTE^^.nLines, 0, docTE ) ) -
- ( docTE^^.viewRect.bottom - docTE^^.viewRect.top );
-
- END ELSE
- max := kMaxDocWidth - (docTE^^.viewRect.right - docTE^^.viewRect.left );
-
- IF max < 0 THEN
- max := 0; { check for negative values }
- SetControlMaximum( control, max );
- IF isVert THEN
- value := docTE^^.viewRect.top - docTE^^.destRect.top
- ELSE
- value := docTE^^.viewRect.left - docTE^^.destRect.left;
- IF value < 0 THEN
- value := 0
- ELSE IF value > max THEN
- value := max; { pin the value to within range }
- SetControlValue( control, value );
- IF canRedraw & ( ( max <> oldMax ) | ( value <> oldValue ) ) THEN
- ShowControl( control ); { check to see if the control can be re-drawn }
- END; { AdjustHV }
-
-
-
- {$S Main}
- PROCEDURE AdjustScrollValues( window : WindowPtr; canRedraw : BOOLEAN );
-
- { Simply call the common adjust routine for the vertical and horizontal scrollbars. }
-
- BEGIN { AdjustScrollValues }
- WITH DocumentPeek( window )^ DO BEGIN
- AdjustHV( TRUE, docVScroll, docTE, canRedraw );
- AdjustHV( FALSE, docHScroll, docTE, canRedraw );
- END; { with }
- END; { AdjustScrollValues }
-
-
-
- {$S Main}
- PROCEDURE AdjustScrollSizes( window : WindowPtr );
-
- { Re-calculate the position and size of the viewRect and the scrollbars.
- kScrollTweek compensates for off-by-one requirements of the scrollbars
- to have borders coincide with the growbox. }
-
- VAR
- teRect : Rect;
-
- BEGIN { AdjustScrollSizes }
- GetTERect( window, teRect ); {start with teRect}
- WITH DocumentPeek( window )^, window^.portRect DO BEGIN
- docTE^^.viewRect := teRect;
-
- { AdjustViewRect(docTE) was removed--no longer needed }
-
- MoveControl( docVScroll, right - kScrollbarAdjust, -1 );
- SizeControl( docVScroll, kScrollbarWidth, ( bottom - top ) -
- ( kScrollbarAdjust - kScrollTweek ) );
- MoveControl( docHScroll, -1, bottom - kScrollbarAdjust );
- SizeControl( docHScroll, ( right - left ) - ( kScrollbarAdjust -
- kScrollTweek ), kScrollbarWidth );
- END; { with }
- END; { AdjustScrollSizes }
-
-
-
- {$S Main}
- PROCEDURE AdjustScrollbars( window : WindowPtr; needsResize : BOOLEAN );
-
- { Turn off the controls by jamming a zero into their contrlVis fields
- (HideControl erases them and we don't want that). If the controls are to
- be resized as well, call the procedure to do that, then call the procedure
- to adjust the maximum and current values. Finally re-enable the controls
- by jamming a $FF in their contrlVis fields. }
-
- VAR
- oldMax, oldVal : INTEGER;
-
- BEGIN { AdjustScrollbars }
- WITH DocumentPeek( window )^ DO BEGIN
- docVScroll^^.contrlVis := kControlInvisible; { turn them off }
- docHScroll^^.contrlVis := kControlInvisible;
- IF needsResize THEN { move and size if needed }
- AdjustScrollSizes( window );
- AdjustScrollValues( window, NOT needsResize ); { fool with max and current value }
- { Now, restore visibility in case we never had to ShowControl during adjustment }
- docVScroll^^.contrlVis := kControlVisible; { turn them on }
- docHScroll^^.contrlVis := kControlVisible;
- END;
- END; { AdjustScrollbars }
-
-
-
- {$S Main}
- {$PUSH} {$Z+}
- PROCEDURE PascalClickLoop;
-
- { Gets called from our assembly language routine, AsmClickLoop, which is in
- turn called by the TEClick toolbox routine. Saves the windows clip region,
- sets it to the portRect, adjusts the scrollbar values to match the TE scroll
- amount, then restores the clip region. }
-
- VAR
- window : WindowPtr;
- region : RgnHandle;
-
- BEGIN { PascalClickLoop }
- window := FrontWindow;
- region := NewRgn;
- GetClip( region ); { save the old clip }
- ClipRect( window^.portRect ); { set the new clip }
- AdjustScrollValues( window, TRUE ); { pass TRUE for canRedraw }
- SetClip( region ); { restore the old clip }
- DisposeRgn( region );
- END; { PascalClickLoop }
- {$POP}
-
-
-
- {$S Main}
- {$PUSH} {$Z+}
- FUNCTION GetOldClickLoop : TEClickLoopUPP;
-
- { Gets called from our assembly language routine, AsmClickLoop, which is in
- turn called by the TEClick toolbox routine. It returns the address of the
- default clickLoop routine that was put into the TERec by TEAutoView to
- AsmClickLoop so that it can call it. }
-
- BEGIN { GetOldClickLoop }
- GetOldClickLoop := DocumentPeek( FrontWindow )^.docClick;
- END; { GetOldClickLoop }
- {$POP}
-
-
-
- PROCEDURE AsmClickLoop; EXTERNAL;
-
- { A reference to our assembly language routine that gets attached to the clickLoop
- field of our TE record. }
-
-
-
- {$S Main}
- PROCEDURE DoNew;
-
- { Create a new document and window. }
-
- {Minor changes from TESample--TEStyleNew instead of TENew-makes certain fields in
- the edit record (lineHeight, txFont, and txFace) have value of -1 and alloctes new
- tables to hold style information}
-
- VAR
- good, ignore : BOOLEAN;
- storage : Ptr;
- window : WindowPtr;
- destRect, viewRect : Rect;
-
-
- BEGIN { DoNew }
- storage := NewPtr( SIZEOF( DocumentRecord ) );
- IF storage <> NIL THEN BEGIN
- window := GetNewWindow( rDocWindow, storage, WindowPtr( -1 ) );
- IF window <> NIL THEN BEGIN
- gNumDocuments := gNumDocuments + 1;
- good := FALSE;
- SetPort( window );
- WITH window^, DocumentPeek( window )^ DO BEGIN
- GetTERect( window, viewRect );
- destRect := viewRect;
- destRect.right := destRect.left + kMaxDocWidth;
- docTE := TEStyleNew( destRect, viewRect );
- { Use TEStyleNew instead of TENew to initialize TERec correctly }
- IF docTE <> NIL THEN BEGIN
- good := TRUE; {if TENew succeeded, we have a good document}
- TEAutoView(TRUE, docTE);
- docClick := docTE^^.clickLoop;
- docTE^^.clickLoop := @AsmClickLoop;
- END;
- IF good THEN BEGIN
- docVScroll := GetNewControl( rVScroll, window );
- good := ( docVScroll <> NIL );
- END; { if }
- IF good THEN BEGIN
- docHScroll := GetNewControl( rHScroll, window );
- good := ( docHScroll <> NIL );
- END; { if }
- IF good THEN BEGIN
- AdjustScrollValues( window, FALSE );
- ShowWindow( window ); { if the document is good, make the window visible }
- END ELSE BEGIN
- ignore := DoCloseWindow( window ); { otherwise regret we ever created it... }
- AlertUser( eNoWindow ); { and tell user }
- END { if }
- END; { with }
- END ELSE
- DisposePtr( storage ); { get rid of the storage if it is never used }
- END; { if }
- END; { DoNew }
-
-
-
- {$S Main}
- PROCEDURE BigBadError( error : INTEGER );
- BEGIN
- AlertUser( error );
- ExitToShell;
- END;
-
-
-
- {$S Initialize}
- PROCEDURE Initialize;
-
- { Set up the whole world, including global variables, Toolbox managers,
- menus, and a single blank document.}
-
- {If an error is detected, instead of merely doing an ExitToShell,
- which leaves the user without much to go on, we call AlertUser, which puts
- up a simple alert that just says an error occurred and then calls ExitToShell.
- Since there is no other cleanup needed at this point if an error is detected,
- this form of error- handling is acceptable. If more sophisticated error recovery
- is needed, an exception mechanism, such as is provided by Signals, can be used.}
-
-
- VAR
- menuBar : Handle;
- total, contig : LongInt;
- ignoreResult : BOOLEAN;
- event : EventRecord;
- count, ignoreError : INTEGER;
-
- PROCEDURE BigBadError( error : INTEGER );
- BEGIN
- AlertUser( error );
- ExitToShell;
- END;
-
- BEGIN { Initialize }
- gInBackground := FALSE;
-
- InitGraf(@qd.thePort);
- InitFonts;
- InitWindows;
- InitMenus;
- TEInit;
- InitDialogs(NIL);
- InitCursor;
-
- FOR count := 1 TO 3 DO
- ignoreResult := EventAvail(everyEvent, event);
- ignoreError := SysEnvirons(kSysEnvironsVersion, gMac);
- IF gMac.machineType < 0 THEN BigBadError(eWrongMachine);
- gHasWaitNextEvent := TrapAvailable(_WaitNextEvent, ToolTrap);
-
-
- IF ORD( GetApplLimit ) - ORD( ApplicationZone ) < kMinHeap THEN
- BigBadError( eSmallSize );
- PurgeSpace( total, contig );
- IF total < kMinSpace THEN
- IF UnloadScrap <> noErr THEN
- BigBadError( eNoMemory )
- ELSE BEGIN
- PurgeSpace( total, contig );
- IF total < kMinSpace THEN
- BigBadError( eNoMemory );
- END; { if }
-
- menuBar := GetNewMBar( rMenuBar ); { read menus into menu bar }
- IF menuBar = NIL THEN
- BigBadError( eNoMemory );
- SetMenuBar( menuBar ); { install menus }
- DisposeHandle( menuBar );
- AppendResMenu( GetMenuHandle( mApple ), 'DRVR' ); { add DA names to Apple menu }
- AppendResMenu( GetMenuHandle( mFont ),'FONT' ); { add Font names to Font Menu }
- DrawMenuBar;
- gNumDocuments := 0;
-
- { do other initialization here }
- { set up printer stuff-this will allow the default pageSetup parameters to be used, so if
- the used decides to print with out using pageSetup everything will be okay }
-
- gPrinterRecord := THPrint( NewHandle( SizeOF( TPrint ) ) ); {allocate a print record}
- IF gPrinterRecord <> NIL THEN BEGIN {if we're successful then setup the default settings}
- PrOpen; {open the record }
- PrintDefault( gPrinterRecord ); { load in default settings }
- PrClose; { close it up }
- END; { if }
-
- DoNew; { create a single empty document }
- END; {Initialize}
-
-
-
- {$S Main}
- PROCEDURE PrintText( hTE : TEHandle );
-
- { Prints the edit record. Opens a printer port, calculates the numbers of lines
- per page (it may be different for each page depending on the the text styles) and
- then calls TEUpdate for the page, scroll a page and TEUpdate, etc. }
-
- CONST
- Margins = 20; { page margins }
-
- VAR
- totalLines : INTEGER; { number of lines in text }
- rView : Rect; { viewRect for TERect }
- oldPort : grafPtr; { hold original grafPtr }
- oldView : Rect; { hold original viewRect }
- oldDest : Rect; { hold original destRect }
- totalHeight : INTEGER; { lineHeight for TERec }
- currentLine : INTEGER; { what line are we on }
- scrollAmount : INTEGER; { how much we scroll by }
- zeroRect : Rect; { 0,0,0,0 rect used in clipRect }
-
- thePrinterStatus : TPrStatus; { printer status }
- openPrintManager : BOOLEAN; { flag if print manager can be opened okay }
- abort : BOOLEAN; { flag if cmd-period is hit to exit routine }
- viewHeight : INTEGER; { temp that has the viewRect height+1 to test conditions }
-
-
- BEGIN { PrintText }
- OpenPrintManager := FALSE; {printer not open yet}
- IF gPrinterRecord <> NIL THEN BEGIN { do we have a legitimate record?}
- PrOpen; {open mr. print record if okay}
- IF PrJobDialog( gPrinterRecord ) THEN BEGIN {bring up job dialog}
- GetPort( oldPort ); { save the old stuff to restore later }
- oldView := hTE^^.viewRect;
- oldDest := hTE^^.destRect;
- gPrinterPort := PrOpenDoc( gPrinterRecord, NIL, NIL );
- OpenPrintManager := ( PrError = noErr );
- END; { if }
- END; { if }
-
- IF OpenPrintManager THEN BEGIN
- SetPort( grafPtr( gPrinterPort ) ); { printer port is now the current port }
- SetRect( zeroRect, 0, 0, 0, 0 );
-
- rView := gPrinterRecord^^.PrInfo.rPage; { get the size of the page rectangle }
- InsetRect( rView, Margins, Margins ); { adjust it for the margins }
- hTE^^.inPort := GrafPtr( gPrinterPort ); { force TE to look at the printer port }
- hTE^^.destRect := rView;
- hTE^^.viewRect := rView; { set new view and dest rects to the TERec }
- TECalText( hTE ); { recalculate our lineStarts array with the new rects }
- totalLines := hTE^^.nLines; { get the number of lines in the newly sized TERec }
- totalHeight := TEGetHeight( totalLines, 0, hTE );
- hTE^^.destRect.bottom := hTE^^.destRect.top + totalHeight; { how tall our destRect is }
-
- abort := FALSE;
- currentLine := 1; { TextEdit sez that TEGetHeight is 1 not 0 based }
-
- WHILE ( NOT ( abort ) AND ( currentLine <= totalLines ) ) DO BEGIN
- PrOpenPage( gPrinterPort, NIL );
- scrollAmount := 0;
- ClipRect( gPrinterRecord^^.PrInfo.rPage ); { Open clipping so text will be drawn }
-
- viewHeight := hTE^^.viewRect.bottom - hTE^^.viewRect.top + 1;
-
- { figure out how many lines there are per page }
- WHILE ((( scrollAmount + TEGetHeight( currentLine, currentLine, hTE ) ) <= viewHeight )
- AND ( currentLine <= totalLines ) ) DO BEGIN
- scrollAmount := scrollAmount + TEGetHeight( currentLine, currentLine, hTE );
- currentLine := currentLine + 1;
- END; { while }
-
- hTE^^.viewRect.bottom := scrollAmount + Margins; { Add margins since top has a margin }
- TEDeactivate( hTE ); { Deactive the edit record so we don't print the cursor or selection range }
- TEUpdate( hTE^^.viewRect, hTE ); { print the page }
- ClipRect( zeroRect ); { Close clipping so that TEScroll doesn't redraw the text }
- TEScroll( 0, -scrollAmount, hTE ); { scroll the page so we can print the next one }
- hTE^^.viewRect.bottom := rView.bottom; { reset bottom to full page }
-
- IF prError = iPrAbort THEN
- abort := TRUE;
- PrClosePage( gPrinterPort ); { close everything up }
- END; { while }
-
- PrCloseDoc( gPrinterPort );
- IF ( gPrinterRecord^^.prJob.bJDocLoop = bSpoolLoop ) AND ( PrError = noErr ) THEN
- PrPicFile( gPrinterRecord, NIL, NIL, NIL, thePrinterStatus );
- PrClose;
- SetPort( oldPort );
- hTE^^.inPort := oldPort;
- hTE^^.viewRect := oldView; { restore the old stuff when we are done }
- hTE^^.destRect := oldDest;
- TEUpdate( hTE^^.viewRect, hTE ); { update everything after resetting the port }
- END; { if }
- END; { PrintText }
-
-
-
- {$S Main}
- PROCEDURE Terminate;
-
- { Clean up the application and exit. We close all of the windows so that
- they can update their documents, if any. }
-
- VAR
- aWindow : WindowPtr;
- closed : BOOLEAN;
-
- BEGIN { Terminate }
- closed := TRUE;
- REPEAT
- aWindow := FrontWindow; { get the current front window }
- IF aWindow <> NIL THEN
- closed := DoCloseWindow( aWindow ); { close this window }
- UNTIL ( NOT closed ) | ( aWindow = NIL ); { do all windows }
- IF closed THEN
- ExitToShell; { exit if no cancellation }
- END; { Terminate }
-
-
-
- {$S Main}
- PROCEDURE AdjustMenus;
-
- VAR
- window : WindowPtr;
- menu : MenuHandle;
- offset : LONGINT;
- undo : BOOLEAN; { flag to enable/disable undo command }
- cutCopyClear : BOOLEAN; { flag to enable/disable editing commands }
- paste : BOOLEAN;
- selectAll : BOOLEAN;
-
- doPrint : BOOLEAN; { flag to enable/disable printing item }
-
- te : TEHandle; { local te handle }
- mode : INTEGER; { current style }
-
-
- BEGIN
- window := FrontWindow;
-
- menu := GetMenuHandle( mFile );
- IF gNumDocuments < kMaxOpenDocuments THEN
- EnableItem( menu, iNew ) { New is enabled when we can open more documents }
- ELSE
- DisableItem( menu, iNew );
-
- IF window <> NIL THEN { Close is enabled when there is a window to close }
- EnableItem( menu, iClose )
- ELSE
- DisableItem( menu, iClose );
-
- menu := GetMenuHandle( mEdit );
- undo := FALSE;
- cutCopyClear := FALSE;
- paste := FALSE;
- selectAll := FALSE;
- doPrint := FALSE;
-
- IF IsDAWindow( window ) THEN BEGIN
- undo := TRUE; { all editing is enabled for DA windows }
- cutCopyClear := TRUE;
- paste := TRUE;
- selectAll := TRUE;
- END ELSE IF IsAppWindow( window ) THEN BEGIN
- WITH DocumentPeek( window )^.docTE^^ DO
- IF selStart < selEnd THEN BEGIN
- cutCopyClear := TRUE;
- END; { if }
- { Cut, Copy, and Clear is enabled for app. windows with selections }
- IF GetScrap( NIL, 'TEXT', offset ) > 0 THEN
- paste := TRUE; { Paste is enabled for app. windows }
-
- selectAll := TRUE;
- doPrint := TRUE;
-
- mode := doFace;
- menu := GetMenuHandle( mStyle );
- IF TEContinuousStyle( mode, gTxStyle, DocumentPeek( window )^.docTE ) THEN BEGIN
- CheckItem( menu, iPlain, gTxStyle.tsface = [] );
- CheckItem( menu, iBold, bold in gTxStyle.tsFace );
- CheckItem( menu, iItalic, italic in gTxStyle.tsFace );
- CheckItem( menu, iUnderline, underline in gTxStyle.tsFace );
- CheckItem( menu, iOutline, outline in gTxStyle.tsFace );
- CheckItem( menu, iShadow, shadow in gTxStyle.tsFace );
- END ELSE BEGIN
- CheckItem( menu, iPlain, FALSE );
- CheckItem( menu, iBold, FALSE );
- CheckItem( menu, iItalic, FALSE );
- CheckItem( menu, iUnderline, FALSE );
- CheckItem( menu, iOutline, FALSE );
- CheckItem( menu, iShadow, FALSE );
- END; { if }
-
- END; { if }
- menu := GetMenuHandle( mEdit );
-
- IF undo THEN
- EnableItem( menu, iUndo )
- ELSE
- DisableItem( menu, iUndo );
-
- IF cutCopyClear THEN BEGIN
- EnableItem( menu, iCut );
- EnableItem( menu, iCopy );
- EnableItem( menu, iClear );
- END ELSE BEGIN
- DisableItem( menu, iCut );
- DisableItem( menu, iCopy );
- DisableItem( menu, iClear );
- END; { if }
-
-
- IF paste THEN
- EnableItem( menu, iPaste )
- ELSE
- DisableItem( menu, iPaste );
-
- IF selectAll THEN
- EnableItem( menu, iSelectAll )
- ELSE
- DisableItem( menu, iSelectAll );
-
-
- menu := GetMenuHandle( mFile );
- IF doPrint THEN BEGIN
- EnableItem( menu, iPageSetup );
- EnableItem( menu, iPrint );
- END ELSE BEGIN
- DisableItem( menu, iPageSetup );
- DisableItem( menu, iPrint );
- END; { if }
-
-
- END; { AdjustMenus }
-
-
-
- {$S Main}
- PROCEDURE DoMenuCommand( menuResult : LONGINT );
-
- { This is called when an item is chosen from the menu bar (after calling
- MenuSelect or MenuKey). It does the right thing for each command. }
-
- VAR
- menuID, menuItem : INTEGER;
- itemHit, daRefNum : INTEGER;
- daName : Str255;
-
- tempStr : Str255;
- menu : MenuHandle;
- anIntPtr : ^INTEGER;
-
- ignoreResult, saveErr : OSErr;
- handledByDA : BOOLEAN;
- te : TEHandle;
- window : WindowPtr;
- ignore : BOOLEAN;
- aHandle : Handle;
- oldSize, newSize : LONGINT;
- total, contig : LONGINT;
-
-
- BEGIN
- window := FrontWindow;
- menuID := HiWord( menuResult ); { use built-ins (for efficiency)... }
- menuItem := LoWord( menuResult ); { to get menu item number and menu number }
- te := DocumentPeek( window )^.docTE;
-
- CASE menuID OF
-
- mApple:
- CASE menuItem OF
- iAbout: {bring up alert for About}
- itemHit := Alert(rAboutAlert, NIL);
- OTHERWISE BEGIN { all non-About items in this menu are DAs }
- GetMenuItemText( GetMenuHandle( mApple ), menuItem, daName );
- daRefNum := OpenDeskAcc( daName );
- END; { otherwise }
- END; { case }
-
- mFile:
- CASE menuItem OF
- iNew:
- DoNew;
- iClose:
- ignore := DoCloseWindow( window ); { we don't care if cancelled }
- iPageSetup: BEGIN
- PrOpen;
- IF PrError = noErr THEN
- ignore := PrStlDialog( gPrinterRecord );
- PrClose;
- END; { iPageSetup }
- iPrint:
- PrintText( te );
- iQuit:
- Terminate;
- END; { case }
-
- mEdit: BEGIN { call SystemEdit for DA editing & MultiFinder }
- IF NOT SystemEdit( menuItem -1 ) THEN BEGIN
- CASE menuItem OF
-
- iCut: BEGIN
- IF ZeroScrap = noErr THEN BEGIN
- PurgeSpace( total, contig );
- IF ( te^^.selEnd - te^^.selStart ) + kTESlop > contig THEN
- AlertUser( eNoSpaceCut )
- ELSE BEGIN
- TECut( te );
- END; { if }
- END; { if }
- END; { iCut }
-
- iCopy: BEGIN
- IF ZeroScrap = noErr THEN BEGIN
- TECopy( te );
- END; { if }
- END; { iCopy }
-
- iPaste: BEGIN
- IF TEGetScrapLength + ( te^^.teLength -
- ( te^^.selEnd - te^^.selStart ) ) > kMaxTELength THEN
- AlertUser( eExceedPaste )
- ELSE BEGIN
- aHandle := Handle( TEGetText( te ) );
- oldSize := GetHandleSize( aHandle );
- newSize := oldSize + TEGetScrapLength + kTESlop;
- SetHandleSize( aHandle, newSize );
- saveErr := MemError;
- SetHandleSize( aHandle, oldSize );
- IF saveErr <> noErr THEN
- AlertUser( eNoSpacePaste )
- ELSE
- TEStylePaste( te );
- END; { if }
- END; { iPaste }
-
- iClear:
- TEDelete( te );
-
- iSelectAll:
- TESetSelect( 0, te^^.teLength, te );
-
- END; { case }
- if menuItem <> iCopy then
- AdjustScrollBars( window, FALSE );
- END; { if }
- END; { mEdit }
-
- mFont :
- BEGIN { mFont }
- GetMenuItemText( GetMenuHandle( mFont ), menuItem, gFontName );
- getFNum( gFontName, gFontID );
- gTxStyle.tsFont := gFontID;
- TESetStyle( doFont, gTxStyle, true, te );
- AdjustScrollBars( window, FALSE );
- END; { mFont }
-
- mFontSize :
- BEGIN { mFontSize }
- CASE menuItem OF
- iNine : gFontSize := 9;
- iTen : gFontSize := 10;
- iTwelve : gFontSize := 12;
- iFourteen : gFontSize := 14;
- iEighteen : gFontSize := 18;
- iTwoFour : gFontSize := 24;
- END; { case }
- gTxStyle.tsSize := gFontSize;
- TESetStyle( doSize, gTxStyle, TRUE, te );
- AdjustScrollBars( window, FALSE );
- END; { mFontSize }
-
- mStyle :
- BEGIN { mStyle }
- WITH gTxStyle DO BEGIN
- CASE menuItem OF
- iPlain :
- BEGIN
- anIntPtr := @gTxStyle.tsFace; { as per Tech Note #131 }
- anIntPtr^ := 0;
- tsFace := [];
- END;
- iBold : tsFace := [bold];
- iItalic : tsFace := [italic];
- iUnderline : tsFace := [underline];
- iOutline : tsFace := [outline];
- iShadow : tsFace := [shadow];
- END; { case }
-
- IF menuItem <> 1 THEN
- TESetStyle( doFace + doToggle, gTxStyle, TRUE, te )
- { if we don't select plain then use doToggle }
- ELSE
- TESetStyle( doFace, gTxStyle, TRUE, te );
- { TESetStyle has problems with plain and doToggle-has no effect!
- so we need to special case it. }
- AdjustScrollBars( window, FALSE );
- END; { with }
- END; { mStyle }
-
- END; { case }
- HiliteMenu( 0 ); { unhighlight what MenuSelect (or MenuKey) hilited }
- END; { DoMenuCommand }
-
-
-
- {$S Main}
- PROCEDURE DrawWindow( window : WindowPtr );
-
- { Draw the contents of an application window. }
-
- BEGIN { DrawWindow }
- SetPort( window );
- WITH window^ DO BEGIN
- EraseRect( portRect ); { as per TextEdit chapter of Inside Macintosh }
- DrawControls( window ); { this ordering makes for a better appearance }
- DrawGrowIcon( window );
- TEUpdate( portRect, DocumentPeek( window )^.docTE );
- END; { with }
- END; { DrawWindow }
-
-
-
- {$S Main}
- FUNCTION GetSleep : LONGINT;
-
- { Calculate a sleep value for WaitNextEvent. This takes into account the things
- that DoIdle does with idle time. }
-
- VAR
- sleep : LONGINT;
- window : WindowPtr;
-
- BEGIN { GetSleep }
- sleep := MAXLONGINT; { default value for sleep }
- IF NOT gInBackground THEN BEGIN { if we are in front... }
- window := FrontWindow; { and the front window is ours... }
- IF IsAppWindow( window ) THEN BEGIN
- WITH DocumentPeek( window )^.docTE^^ DO
- IF selStart = selEnd THEN { and the selection is an insertion point... }
- sleep := GetCaretTime; { we need to blink the insertion point }
- END; { if }
- END; { if }
- GetSleep := sleep;
- END; { GetSleep }
-
-
-
- {$S Main}
- PROCEDURE CommonAction( control : ControlHandle; VAR amount : INTEGER );
-
- { Common algorithm for setting the new value of a control. It returns the actual amount
- the value of the control changed. Note the pinning is done for the sake of returning
- the amount the control value changed. }
-
- VAR
- value, max : INTEGER;
- window : WindowPtr;
-
- BEGIN { CommonAction }
- value := GetControlValue( control ); { get current value }
- max := GetControlMaximum( control ); { and max value }
- amount := value - amount;
- IF amount < 0 THEN
- amount := 0
- ELSE IF amount > max THEN
- amount := max;
- SetControlValue( control, amount );
- amount := value - amount; { calculate true change }
- END; { CommonAction }
-
-
-
- {$S Main}
- PROCEDURE VActionProc( control : ControlHandle; part : INTEGER );
-
- { Determines how much to change the value of the vertical scrollbar by and how
- much to scroll the TE record. }
-
- VAR
- amount : INTEGER;
- window : WindowPtr;
-
- BEGIN { VActionProc }
- IF part <> 0 THEN BEGIN
- window := control^^.contrlOwner;
- WITH DocumentPeek( window )^, DocumentPeek( window )^.docTE^^ DO BEGIN
- CASE part OF
- inUpButton, inDownButton :
- amount := 24;
- inPageUp, inPageDown :
- amount := viewRect.bottom - viewRect.top; { one page }
- END; { case }
- IF ( part = inDownButton ) | ( part = inPageDown ) THEN
- amount := -amount; { reverse direction }
- CommonAction( control, amount );
- IF amount <> 0 THEN
- TEScroll( 0, amount, docTE );
- END; { with }
- END; { if }
- END; { VActionProc }
-
-
-
- {$S Main}
- PROCEDURE HActionProc( control : ControlHandle; part : INTEGER );
-
- { Determines how much to change the value of the horizontal scrollbar by and how
- much to scroll the TE record. }
-
- VAR
- amount : INTEGER;
- window : WindowPtr;
-
- BEGIN { HActionProc }
- IF part <> 0 THEN BEGIN
- window := control^^.contrlOwner;
- WITH DocumentPeek( window )^, DocumentPeek( window )^.docTE^^ DO BEGIN
- CASE part OF
- inUpButton, inDownButton :
- amount := kButtonScroll; { a few pixels }
- inPageUp, inPageDown :
- amount := viewRect.right - viewRect.left; { a page }
- END; { case }
- IF ( part = inDownButton ) | ( part = inPageDown ) THEN
- amount := -amount; { reverse direction }
- CommonAction( control, amount );
- IF amount <> 0 THEN
- TEScroll( amount, 0, docTE );
- END; { with }
- END; { if }
- END; { HActionProc }
-
-
-
- {$S Main}
- PROCEDURE DoIdle;
-
- { This is called whenever we get an null event or a mouse-moved event.
- It takes care of necessary periodic actions. For this program, it calls TEIdle. }
-
- VAR
- window : WindowPtr;
-
- BEGIN { DoIdle }
- window := FrontWindow;
- IF IsAppWindow( window ) THEN
- TEIdle( DocumentPeek( window )^.docTE );
- END; { DoIdle }
-
-
-
- {$S Main}
- PROCEDURE DoKeyDown( event : EventRecord );
-
- { This is called for any keyDown or autoKey events, except when the
- Command key is held down. It looks at the frontmost window to decide what
- to do with the key typed. }
-
- VAR
- window : WindowPtr;
- key : CHAR;
- te : TEHandle;
-
- BEGIN
- window := FrontWindow;
- IF IsAppWindow( window ) THEN BEGIN
- te := DocumentPeek( window)^.docTE;
- key := CHR( BAnd( event.message, charCodeMask ) );
- IF ( key = CHR(kDelChar ) ) | { don't count deletes }
- ( te^^.teLength - ( te^^.selEnd - te^^.selStart )
- + 1 < kMaxTELength ) THEN BEGIN { but check haven't gone past }
- TEKey( key, te );
- AdjustScrollbars( window, FALSE );
- END ELSE
- AlertUser( eExceedChar );
- END; { if }
- END; { DoKeyDown }
-
-
-
- {$S Main}
- PROCEDURE DoContentClick( window : WindowPtr; event : EventRecord );
-
- { Called when a mouseDown occurs in the content of a window. }
-
- VAR
- mouse : Point;
- control : ControlHandle;
- part, value : INTEGER;
- shiftDown : BOOLEAN;
- teRect : Rect;
- upp : ControlActionUPP;
-
- BEGIN { DoContentClick }
- IF IsAppWindow( window ) THEN BEGIN
- SetPort( window );
- mouse := event.where; { get the click position }
- GlobalToLocal( mouse ); { convert to local coordinates }
-
- GetTERect( window, teRect );
- IF PtInRect( mouse, teRect ) THEN BEGIN
- shiftDown := BAnd( event.modifiers, shiftKey ) <> 0; { extend if Shift is down }
- TEClick( mouse, shiftDown, DocumentPeek( window )^.docTE );
- END ELSE BEGIN
- part := FindControl( mouse, window, control );
- WITH DocumentPeek( window )^ DO
- CASE part OF
- 0:; { do nothing for viewRect case }
- inThumb: BEGIN
- value := GetControlValue( control );
- part := TrackControl( control, mouse, NIL );
- IF part <> 0 THEN BEGIN
- value := value - GetControlValue( control );
- IF value <> 0 THEN
- IF control = docVScroll THEN
- TEScroll( 0, value, docTE )
- ELSE
- TEScroll( value, 0, docTE );
- END; { if }
- END; { inThumb }
- OTHERWISE { must be page or button }
- BEGIN
- IF control = docVScroll THEN
- upp := NewControlActionProc(@VActionProc)
- ELSE
- upp := NewControlActionProc(@HActionProc);
- value := TrackControl(control, mouse, upp);
- DisposeRoutineDescriptor(upp);
- END;
- END; { case }
- END; { if }
- END; { if }
- END; { DoContentClick }
-
-
-
- {$S Main}
- PROCEDURE ResizeWindow( window : WindowPtr );
-
- { Called when the window has been resized to fix up the controls and content }
-
- BEGIN { ResizeWindow }
- WITH window^ DO BEGIN
- AdjustScrollbars( window, TRUE );
- AdjustTE( window );
- InvalRect( portRect );
- END;
- END; { ResizeWindow }
-
-
-
- {$S Main}
- PROCEDURE GetLocalUpdateRgn( window : WindowPtr; localRgn : RgnHandle );
-
- { Returns the update region in local coordinates }
-
- BEGIN { GetLocalUpdateRgn }
- CopyRgn( WindowPeek( window )^.updateRgn, localRgn ); { save old update region }
- WITH window^.portBits.bounds DO
- OffsetRgn( localRgn, left, top ); { convert to local coords }
- END; { GetLocalUpdateRgn }
-
-
-
- {$S Main}
- PROCEDURE DoGrowWindow( window : WindowPtr; event : EventRecord );
-
- { Called when a mouseDown occurs in the grow box of an active window. In
- order to eliminate any 'flicker', we want to invalidate only what is
- necessary. Since ResizeWindow invalidates the whole portRect, we save
- the old TE viewRect, intersect it with the new TE viewRect, and
- remove the result from the update region. However, we must make sure
- that any old update region that might have been around gets put back. }
-
- VAR
- growResult : LONGINT;
- tempRect : Rect;
- tempRgn : RgnHandle;
- ignoreResult : BOOLEAN;
-
- BEGIN { DoGrowWindow }
- WITH qd.screenBits.bounds DO
- SetRect( tempRect, kMinDocDim, kMinDocDim, right, bottom ); { set up limiting values }
- growResult := GrowWindow( window, event.where, tempRect );
- IF growResult <> 0 THEN { see if changed size }
- WITH DocumentPeek( window )^, window^ DO BEGIN
- tempRect := docTE^^.viewRect; { save old text box }
- tempRgn := NewRgn;
- GetLocalUpdateRgn( window, tempRgn ); { get localized update region }
- SizeWindow( window, LoWord( growResult ), HiWord( growResult ), TRUE );
- ResizeWindow( window );
- ignoreResult := SectRect( tempRect, docTE^^.viewRect, tempRect ); { find what stayed same }
- ValidRect( tempRect ); { take it out of update }
- InvalRgn( tempRgn ); { put back any prior update }
- DisposeRgn( tempRgn );
- END; { with }
- END; { DoGrowWindow }
-
-
-
- {$S Main}
- PROCEDURE DoZoomWindow( window : WindowPtr; part : INTEGER );
-
- { Called when a mouseClick occurs in the zoom box of an active window.
- Everything has to get re-drawn here, so we don't mind that
- ResizeWindow invalidates the whole portRect. }
-
- BEGIN { DoZoomWindow }
- WITH window^ DO BEGIN
- EraseRect( portRect );
- ZoomWindow( window, part, ( window = FrontWindow ) );
- ResizeWindow( window );
- END; { with }
- END; { DoZoomWindow }
-
-
-
- {$S Main}
- PROCEDURE DoUpdate( window : WindowPtr );
-
- { This is called when an update event is received for a window.
- It calls DrawWindow to draw the contents of an application window,
- but only if the visRgn is non-empty; for efficiency reasons,
- not because it is required. }
-
- BEGIN { DoUpdate }
- IF IsAppWindow( window ) THEN BEGIN
- BeginUpdate( window ); { this sets up the visRgn }
- IF NOT EmptyRgn( window^.visRgn ) THEN { draw if updating needs to be done }
- DrawWindow( window );
- EndUpdate( window );
- END; { if }
- END; { DoUpdate }
-
-
-
- {$S Main}
- PROCEDURE DoActivate( window : WindowPtr; becomingActive : BOOLEAN );
-
- { This is called when a window is activated or deactivated. }
-
- VAR
- tempRgn, clipRgn : RgnHandle;
- growRect : Rect;
-
- BEGIN { DoActivate }
- IF IsAppWindow( window ) THEN
- WITH DocumentPeek( window )^ DO
- IF becomingActive THEN BEGIN
- { since we don’t want TEActivate to draw a selection in an area where
- we’re going to erase and redraw, we’ll clip out the update region
- before calling it. }
- tempRgn := NewRgn;
- clipRgn := NewRgn;
- GetLocalUpdateRgn( window, tempRgn ); { get localized update region }
- GetClip( clipRgn );
- DiffRgn( clipRgn, tempRgn, tempRgn ); { subtract updateRgn from clipRgn }
- SetClip( tempRgn );
- TEActivate( docTE ); { let TE do its thing }
- SetClip( clipRgn ); { restore the full-blown clipRgn }
- DisposeRgn( tempRgn );
- DisposeRgn( clipRgn );
-
- {the controls need to be redrawn on activation:}
- docVScroll^^.contrlVis := kControlVisible;
- docHScroll^^.contrlVis := kControlVisible;
- InvalRect( docVScroll^^.contrlRect );
- InvalRect( docHScroll^^.contrlRect );
- { the growbox needs to be redrawn on activation: }
- growRect := window^.portRect;
- WITH growRect DO BEGIN
- top := bottom - kScrollbarAdjust; { adjust for the scrollbars }
- left := right - kScrollbarAdjust;
- END; { with }
- InvalRect( growRect );
- END ELSE BEGIN
- TEDeactivate( docTE );
- { the controls should be hidden immediately on deactivation: }
- HideControl( docVScroll );
- HideControl( docHScroll );
- { the growbox should be changed immediately on deactivation: }
- DrawGrowIcon( window );
- END; { if }
- END; { DoActivate }
-
-
-
- {$S Main}
- PROCEDURE GetGlobalMouse(VAR mouse: Point);
-
- {Get the global coordinates of the mouse. When you call OSEventAvail
- it will return either a pending event or a null event. In either case,
- the where field of the event record will contain the current position
- of the mouse in global coordinates and the modifiers field will reflect
- the current state of the modifiers. Another way to get the global
- coordinates is to call GetMouse and LocalToGlobal, but that requires
- being sure that thePort is set to a valid port.}
-
- VAR
- event : EventRecord;
-
- BEGIN
- IF OSEventAvail(kNoEvents, event) THEN; {we aren't interested in any events}
- mouse := event.where; {just the mouse position}
- END;
-
-
-
- {$S Main}
- PROCEDURE AdjustCursor( mouse : Point; region : RgnHandle );
-
- { Change the cursor's shape, depending on its position. This also calculates a region
- that includes the cursor for WaitNextEvent. }
-
- VAR
- window : WindowPtr;
- arrowRgn : RgnHandle;
- iBeamRgn : RgnHandle;
- iBeamRect : Rect;
-
- BEGIN { AdjustCursor }
- window := FrontWindow; { we only adjust the cursor when we are in front }
- IF ( NOT gInBackground ) AND ( NOT IsDAWindow( window ) ) THEN BEGIN
- { calculate regions for different cursor shapes}
- arrowRgn := NewRgn;
- iBeamRgn := NewRgn;
-
- { start with a big, big rectangular region }
- SetRectRgn( arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos );
-
- { calculate iBeamRgn }
- IF IsAppWindow( window ) THEN BEGIN
- iBeamRect := DocumentPeek( window )^.docTE^^.viewRect;
- SetPort( window ); { make a global version of the viewRect }
- WITH iBeamRect DO BEGIN
- LocalToGlobal( topLeft );
- LocalToGlobal( botRight );
- END; { with }
- RectRgn( iBeamRgn, iBeamRect );
- WITH window^.portBits.bounds DO
- SetOrigin( -left, -top );
- SectRgn( iBeamRgn, window^.visRgn, iBeamRgn );
- SetOrigin( 0, 0 );
- END; { if }
-
- { subtract other regions from arrowRgn }
- DiffRgn( arrowRgn, iBeamRgn, arrowRgn );
-
- {change the cursor and the region parameter}
- IF PtInRgn( mouse, iBeamRgn ) THEN BEGIN
- SetCursor( GetCursor( iBeamCursor )^^ );
- CopyRgn( iBeamRgn, region );
- END ELSE BEGIN
- SetCursor( qd.arrow );
- CopyRgn( arrowRgn, region );
- END; { if }
-
- { get rid of our local regions }
- DisposeRgn( arrowRgn );
- DisposeRgn( iBeamRgn );
- END; { if }
- END; { AdjustCursor }
-
-
-
- {$S Main}
- PROCEDURE DoEvent( event : EventRecord );
-
- { Do the right thing for an event. Determine what kind of event it is, and call
- the appropriate routines. }
-
- VAR
- part, err : INTEGER;
- window : WindowPtr;
- key : CHAR;
- ignore : BOOLEAN;
- aPoint : Point;
-
- BEGIN { DoEvent }
- CASE event.what OF
- nullEvent:
- DoIdle;
- mouseDown: BEGIN
- part := FindWindow( event.where, window );
- CASE part OF
-
- inMenuBar : BEGIN
- AdjustMenus;
- DoMenuCommand( MenuSelect( event.where ) );
- END; { inMenuBar }
-
- inSysWindow :
- SystemClick( event, window );
-
- inContent :
- IF window <> FrontWindow THEN BEGIN
- SelectWindow(window);
- {DoEvent(event);} {use this line for "do first click"}
- END ELSE
- DoContentClick( window, event );
-
- inDrag :
- DragWindow( window, event.where, qd.screenBits.bounds );
-
- inGrow:
- DoGrowWindow( window, event );
-
- inGoAway:
- IF TrackGoAway( window, event.where ) THEN
- ignore := DoCloseWindow( window ); { we don't care if cancelled }
-
- inZoomIn, inZoomOut:
-
- IF TrackBox(window, event.where, part) THEN
- DoZoomWindow( window, part );
- END; { case }
- END; { mouseDown }
-
- keyDown, autoKey : BEGIN
- key := CHR( BAnd( event.message, charCodeMask ) );
- IF BAnd( event.modifiers, cmdKey ) <> 0 THEN BEGIN { Command key down }
- IF event.what = keyDown THEN BEGIN
- AdjustMenus; { enable/disable/check menu items properly }
- DoMenuCommand( MenuKey( key ) );
- END; { if }
- END ELSE
- DoKeyDown( event );
- END; { keyDown } { call DoActivate with the window and... }
-
- activateEvt: { TRUE for activate, FALSE for deactivate }
- DoActivate( WindowPtr( event.message ), BAND( event.modifiers, activeFlag ) <> 0 );
-
- updateEvt: { call DoUpdate with the window to update }
- DoUpdate( WindowPtr( event.message ) );
-
- diskEvt:
- IF HiWord(event.message) <> noErr THEN BEGIN
- SetPt(aPoint, kDILeft, kDITop);
- err := DIBadMount(aPoint, event.message);
- END;
-
- kOSEvent:
- CASE BAnd(BRotL( event.message, 8 ), $FF ) OF { high byte of message }
- kMouseMovedMessage:
- DoIdle; { mouse moved is also an idle event }
-
- kSuspendResumeMessage: BEGIN
- gInBackground := BAnd( event.message, kResumeMask ) = 0;
- DoActivate( FrontWindow, NOT gInBackground );
- END; { kSuspendResumeMessage }
- END;
- END; { case }
- END; { DoEvent }
-
-
-
- {$S Main}
- PROCEDURE EventLoop;
-
- { Get events forever, and handle them by calling DoEvent.
- Also call AdjustCursor each time through the loop. }
-
- VAR
- cursorRgn : RgnHandle;
- gotEvent : BOOLEAN;
- event : EventRecord;
- mouse : Point;
-
- BEGIN { EventLoop }
- cursorRgn := NewRgn; { we'll pass an empty region to WNE the first time thru }
- REPEAT
- IF gHasWaitNextEvent THEN BEGIN
- GetGlobalMouse(mouse); {since we might go to sleep}
- AdjustCursor(mouse, cursorRgn);
- gotEvent := WaitNextEvent(everyEvent, event, GetSleep, cursorRgn)
- END ELSE BEGIN
- SystemTask;
- gotEvent := GetNextEvent(everyEvent, event);
- END; { if }
- IF gotEvent THEN BEGIN
- AdjustCursor(event.where, cursorRgn);
- DoEvent(event);
- END
- ELSE
- DoIdle;
- UNTIL FALSE; { loop forever }
- END; { EventLoop }
-
-
-
- PROCEDURE _DataInit; EXTERNAL;
-
- { This routine is automatically linked in by the MPW Linker. This external
- reference to it is done so that we can unload its segment, %A5Init. }
-
-
- {$S Main}
- BEGIN { main program }
- UnloadSeg( @_DataInit ); { note that _DataInit must not be in Main! }
- MaxApplZone; { expand the heap so code segments load at the top }
- Initialize; { initialize the program }
- UnloadSeg( @Initialize ); { note that Initialize must not be in Main! }
- EventLoop; { call the main event loop }
- END. { main program }
-